<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./js/lil-gui.module.min.js"></script>
</head>

<body>
    <canvas id="canvas" style="width: 800px; height: 600px;"></canvas>
</body>

<script id="vertex-shader" type="nojs">
    attribute vec2 a_position;

    uniform vec2 u_resolution;
    uniform mat3 u_matrix;

    void main() {

        // 将位置乘以矩阵
        vec2 position = (u_matrix * vec3(a_position, 1)).xy;

        // 通过变换将坐标转换到裁剪空间0-1
        vec2 zeroToOne = position / u_resolution;

        // 将0-1的坐标转换到0-2
        vec2 zeroToTwo = zeroToOne * 2.0;

        // 将0-2的坐标转换到-1-1
        vec2 clipSpace = zeroToTwo - 1.0;

        gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
    }
</script>

<script id="flagment-shader" type="nojs">
    precision mediump float;
    uniform vec4 u_color;

    void main() {
        gl_FragColor = u_color;
    }
</script>

<script type="module">
    var m3 = {
        projection: function (width, height) {
            // Note: This matrix flips the Y axis so that 0 is at the top.
            return [
                2 / width, 0, 0,
                0, -2 / height, 0,
                -1, 1, 1
            ];
        },

        identity: function () {
            return [
                1, 0, 0,
                0, 1, 0,
                0, 0, 1,
            ];
        },

        translation: function (tx, ty) {
            return [
                1, 0, 0,
                0, 1, 0,
                tx, ty, 1,
            ];
        },

        rotation: function (angleInRadians) {
            var c = Math.cos(angleInRadians);
            var s = Math.sin(angleInRadians);
            return [
                c, -s, 0,
                s, c, 0,
                0, 0, 1,
            ];
        },

        scaling: function (sx, sy) {
            return [
                sx, 0, 0,
                0, sy, 0,
                0, 0, 1,
            ];
        },

        multiply: function (a, b) {
            var a00 = a[0 * 3 + 0];
            var a01 = a[0 * 3 + 1];
            var a02 = a[0 * 3 + 2];
            var a10 = a[1 * 3 + 0];
            var a11 = a[1 * 3 + 1];
            var a12 = a[1 * 3 + 2];
            var a20 = a[2 * 3 + 0];
            var a21 = a[2 * 3 + 1];
            var a22 = a[2 * 3 + 2];
            var b00 = b[0 * 3 + 0];
            var b01 = b[0 * 3 + 1];
            var b02 = b[0 * 3 + 2];
            var b10 = b[1 * 3 + 0];
            var b11 = b[1 * 3 + 1];
            var b12 = b[1 * 3 + 2];
            var b20 = b[2 * 3 + 0];
            var b21 = b[2 * 3 + 1];
            var b22 = b[2 * 3 + 2];
            return [
                b00 * a00 + b01 * a10 + b02 * a20,
                b00 * a01 + b01 * a11 + b02 * a21,
                b00 * a02 + b01 * a12 + b02 * a22,
                b10 * a00 + b11 * a10 + b12 * a20,
                b10 * a01 + b11 * a11 + b12 * a21,
                b10 * a02 + b11 * a12 + b12 * a22,
                b20 * a00 + b21 * a10 + b22 * a20,
                b20 * a01 + b21 * a11 + b22 * a21,
                b20 * a02 + b21 * a12 + b22 * a22,
            ];
        },

        translate: function (m, tx, ty) {
            return m3.multiply(m, m3.translation(tx, ty));
        },

        rotate: function (m, angleInRadians) {
            return m3.multiply(m, m3.rotation(angleInRadians));
        },

        scale: function (m, sx, sy) {
            return m3.multiply(m, m3.scaling(sx, sy));
        },
    };
    import { GUI } from './js/lil-gui.module.min.js';

    const gui = new GUI();

    function main() {
        var canvas = document.querySelector("#canvas");
        canvas.width = 800;
        canvas.height = 600;

        const gl = document.getElementById('canvas').getContext('webgl');
        if (!gl) {
            console.log('Failed to get the rendering context for WebGL');
            return;
        }

        const vertexShader = createShader(gl, gl.VERTEX_SHADER, document.getElementById('vertex-shader').text);
        const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, document.getElementById('flagment-shader').text);

        const shaderProgram = initShaderProgram(gl, vertexShader, fragmentShader);

        const positionAttributeLocation = gl.getAttribLocation(shaderProgram, 'a_position');

        const resolutionUniformLocation = gl.getUniformLocation(shaderProgram, 'u_resolution');

        const colorUniformLocation = gl.getUniformLocation(shaderProgram, "u_color");

        const matrixLocation = gl.getUniformLocation(shaderProgram, "u_matrix");

        // attribute 需要从缓冲区中获取数据
        const positionBuffer = gl.createBuffer();

        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

        // 通过bufferData将数据传入缓冲区
        setGeometry(gl);

        gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

        // 设置背景颜色蓝色
        gl.clearColor(0, 0, 0, 255);
        // gl.clearColor(0, 1, 1, 0);
        gl.clear(gl.COLOR_BUFFER_BIT);

        gl.useProgram(shaderProgram);

        gl.enableVertexAttribArray(positionAttributeLocation); // 开启attribute变量

        gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);
        gl.uniform4f(colorUniformLocation, Math.random(), Math.random(), Math.random(), 1);

        // 告诉attribute变量从缓冲区中获取数据
        const size = 2; // 每次迭代运行提取两个单位数据
        const type = gl.FLOAT; // 每个单位的数据类型是32位浮点型
        const normalize = false; // 不需要归一化数据
        const stride = 0; // 0 = 移动单位数量 * 每个单位占用内存（sizeof(type)）
        var offset = 0; // 从缓冲区何处开始获取数据
        gl.vertexAttribPointer(positionAttributeLocation, size, type, normalize, stride, offset);

        const primitiveType = gl.TRIANGLES;
        var offset = 0;
        var count = 18;

        let currentPos = {
            x: 60,
            y: 40,
            rotateAngle: 0,
            width: 100,
            height: 60,
            scale: [.85, .85]
        }

        // 初始矩阵
        var matrix = m3.identity();

        for (var i = 0; i < 5; ++i) {
            // 矩阵相乘
            matrix = m3.translate(matrix, currentPos.x, currentPos.y);
            matrix = m3.rotate(matrix, currentPos.rotateAngle * Math.PI / 180);
            matrix = m3.scale(matrix, currentPos.scale[0], currentPos.scale[1]);

            // 设置矩阵
            gl.uniformMatrix3fv(matrixLocation, false, matrix);

            // 绘制图形
            gl.drawArrays(primitiveType, offset, count);
        }

        const resolutionSize = {
            width: gl.canvas.width,
            height: gl.canvas.height
        }

        gui.add(currentPos, 'x', 0, resolutionSize.width - currentPos.width).name('X位置').onChange(() => {
            gl.clearColor(0, 0, 0, 255);
            gl.clear(gl.COLOR_BUFFER_BIT);
            var translationMatrix = m3.translation(currentPos.x, currentPos.y);
            var rotationMatrix = m3.rotation(currentPos.rotateAngle * Math.PI / 180);
            var scaleMatrix = m3.scaling(currentPos.scale[0], currentPos.scale[1]);

            // Multiply the matrices.
            // 初始矩阵
            var matrix = m3.identity();

            for (var i = 0; i < 5; ++i) {
                // 矩阵相乘
                matrix = m3.multiply(matrix, translationMatrix);
                matrix = m3.multiply(matrix, rotationMatrix);
                matrix = m3.multiply(matrix, scaleMatrix);

                console.log(matrix);

                // 设置矩阵
                gl.uniformMatrix3fv(matrixLocation, false, matrix);

                // 绘制图形
                gl.drawArrays(primitiveType, offset, count);
            }

        })

        gui.add(currentPos, 'y', 0, resolutionSize.height - currentPos.height).name('Y位置').onChange(() => {
            gl.clearColor(0, 0, 0, 255);
            gl.clear(gl.COLOR_BUFFER_BIT);
            var translationMatrix = m3.translation(currentPos.x, currentPos.y);
            var rotationMatrix = m3.rotation(currentPos.rotateAngle * Math.PI / 180);
            var scaleMatrix = m3.scaling(currentPos.scale[0], currentPos.scale[1]);

            // Multiply the matrices.
            // 初始矩阵
            var matrix = m3.identity();

            for (var i = 0; i < 5; ++i) {
                // 矩阵相乘
                matrix = m3.multiply(matrix, translationMatrix);
                matrix = m3.multiply(matrix, rotationMatrix);
                matrix = m3.multiply(matrix, scaleMatrix);

                console.log(matrix);

                // 设置矩阵
                gl.uniformMatrix3fv(matrixLocation, false, matrix);

                // 绘制图形
                gl.drawArrays(primitiveType, offset, count);
            }
        })

        gui.add(currentPos, 'rotateAngle', 0, 360).name('旋转角度').onChange(() => {

            gl.clearColor(0, 0, 0, 255);
            gl.clear(gl.COLOR_BUFFER_BIT);
            var translationMatrix = m3.translation(currentPos.x, currentPos.y);
            var rotationMatrix = m3.rotation(currentPos.rotateAngle * Math.PI / 180);
            var scaleMatrix = m3.scaling(currentPos.scale[0], currentPos.scale[1]);

            // Multiply the matrices.
            // 初始矩阵
            var matrix = m3.identity();

            for (var i = 0; i < 5; ++i) {
                // 矩阵相乘
                matrix = m3.multiply(matrix, translationMatrix);
                matrix = m3.multiply(matrix, rotationMatrix);
                matrix = m3.multiply(matrix, scaleMatrix);

                console.log(matrix);

                // 设置矩阵
                gl.uniformMatrix3fv(matrixLocation, false, matrix);

                // 绘制图形
                gl.drawArrays(primitiveType, offset, count);
            }
        })
        gui.add(currentPos.scale, '0', -5, 5).name('x缩放').onChange(() => {

            gl.clearColor(0, 0, 0, 255);
            gl.clear(gl.COLOR_BUFFER_BIT);
            var translationMatrix = m3.translation(currentPos.x, currentPos.y);
            var rotationMatrix = m3.rotation(currentPos.rotateAngle * Math.PI / 180);
            var scaleMatrix = m3.scaling(currentPos.scale[0], currentPos.scale[1]);

            // Multiply the matrices.
            // 初始矩阵
            var matrix = m3.identity();

            for (var i = 0; i < 5; ++i) {
                // 矩阵相乘
                matrix = m3.multiply(matrix, translationMatrix);
                matrix = m3.multiply(matrix, rotationMatrix);
                matrix = m3.multiply(matrix, scaleMatrix);

                console.log(matrix);

                // 设置矩阵
                gl.uniformMatrix3fv(matrixLocation, false, matrix);

                // 绘制图形
                gl.drawArrays(primitiveType, offset, count);
            }
        })

    }


    function setGeometry(gl) {
        gl.bufferData(
            gl.ARRAY_BUFFER,
            new Float32Array([
                // 左竖
                0, 0,
                30, 0,
                0, 150,
                0, 150,
                30, 0,
                30, 150,

                // 上横
                30, 0,
                100, 0,
                30, 30,
                30, 30,
                100, 0,
                100, 30,

                // 中横
                30, 60,
                67, 60,
                30, 90,
                30, 90,
                67, 60,
                67, 90,
            ]),
            gl.STATIC_DRAW);
    }

    function setRectangle(gl, x, y, width, height) {
        const x1 = x;
        const x2 = x + width;
        const y1 = y;
        const y2 = y + height;

        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
            x1, y1,
            x2, y1,
            x1, y2,
            x1, y2,
            x2, y1,
            x2, y2,
        ]), gl.STATIC_DRAW);
    }

    function createShader(gl, type, source) {
        const shader = gl.createShader(type);
        gl.shaderSource(shader, source);
        gl.compileShader(shader);
        var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
        if (success) {
            return shader;
        }
        gl.deleteShader(shader);
    }

    function initShaderProgram(gl, vertexShader, fragmentShader) {
        const shaderProgram = gl.createProgram();
        gl.attachShader(shaderProgram, vertexShader)
        gl.attachShader(shaderProgram, fragmentShader)
        gl.linkProgram(shaderProgram)
        var success = gl.getProgramParameter(shaderProgram, gl.LINK_STATUS);
        if (success) {
            return shaderProgram;
        }
        gl.deleteProgram(shaderProgram);
    }

    main();




</script>

</html>